import socket
import threading
from queue import Queue
import time  # 新增时间模块用于添加时间戳

# MongoDB检测数据包（官方协议格式）
DETECT_PACKET = bytes([
    0x3F, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xD4, 0x07, 0x00, 0x00,
    0x04, 0x00, 0x00, 0x00, 0x61, 0x64, 0x6D, 0x69,
    0x6E, 0x2E, 0x24, 0x63, 0x6D, 0x64, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x18,
    0x00, 0x00, 0x00, 0x10, 0x6C, 0x69, 0x73, 0x74,
    0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
    0x73, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
])


def check_mongodb(host, port=27017, timeout=5):
    """
    检测MongoDB未授权访问漏洞
    关键判断逻辑：响应包含'local'且不含'errmsg'（避免误报）
    """
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        sock.connect((host, port))

        # 发送检测数据包
        sock.send(DETECT_PACKET)
        response = sock.recv(1024).decode('latin1', errors='ignore')

        # 漏洞判断标准
        if 'local' in response and 'errmsg' not in response:
            return True, f"{host}:{port}"
        return False, ""

    except Exception:
        return False, ""
    finally:
        sock.close()


def worker(target_queue, vulnerable_list, lock):
    """多线程检测工作函数（添加锁机制）"""
    while not target_queue.empty():
        host, port = target_queue.get()
        vulnerable, result = check_mongodb(host, port)
        if vulnerable:
            with lock:  # 使用锁确保线程安全[6,9](@ref)
                vulnerable_list.append(result)
        target_queue.task_done()


def main():
    # 读取目标文件
    targets = []
    try:
        with open('url.txt', 'r') as f:
            for line in f:
                line = line.strip()
                if ':' in line:
                    host, port = line.split(':', 1)
                    targets.append((host, int(port)))
                else:
                    targets.append((line, 27017))  # 默认端口
    except FileNotFoundError:
        print("[错误] 未找到url.txt文件")
        return

    # 多线程检测
    target_queue = Queue()
    vulnerable_list = []
    lock = threading.Lock()  # 创建线程锁[9](@ref)

    for target in targets:
        target_queue.put(target)

    # 创建线程（最多20个）
    thread_count = min(20, len(targets))
    threads = []
    for _ in range(thread_count):
        t = threading.Thread(target=worker, args=(target_queue, vulnerable_list, lock))
        t.daemon = True
        t.start()
        threads.append(t)

    target_queue.join()

    # 输出漏洞结果
    if vulnerable_list:
        print("\n[+] 存在MongoDB未授权访问的URL:")
        for url in vulnerable_list:
            print(f"  - {url}")

        # ==== 关键修改：使用追加模式保存结果 ====
        try:
            # 获取当前时间戳
            timestamp = time.strftime("%Y-%m-%d %H:%M:%S")

            # 使用追加模式写入文件[1,4](@ref)
            with open('mangodb未授权测试.txt', 'a', encoding='utf-8') as f:
                # 添加分隔线和时间戳
                f.write(f"\n\n===== 检测时间: {timestamp} =====\n")

                # 写入本次检测结果
                for url in vulnerable_list:
                    f.write(f"{url}\n")

            print(f"\n[!] 结果已追加保存至 mangodb未授权测试.txt")

        except Exception as e:
            print(f"\n[错误] 保存结果时出错: {str(e)}")
    else:
        print("\n[-] 未发现MongoDB未授权访问漏洞")


if __name__ == "__main__":
    print("开始检测MongoDB未授权访问漏洞...")
    main()